﻿/******************************************************************************
 * 【本类功能概述】                                 					      *
 *  版权所有（C）2017-20XX，米兔网络                                         *
 *  保留所有权利。                                                            *
 ******************************************************************************
 *  作者 : <hughjk>
 *  创建时间:2018年4月23日 17:19:25
 *  文件描述:测试代码
 *****************************************************************************/

using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using UnityEngine;

public class debug
{
    private static uint i = 0;
    public static DateTime time;
    public static Level Showlevel = Level.normal_1;

    /// <summary>
    /// 提示等级
    /// </summary>
    public enum Level
    {
        normal_1,//普通
        warning_2,//警告
        error_3,//错误
    }

    public static void ShowTime()
    {
        if (time != null)
        {
            log(DateTime.UtcNow.Subtract(time).TotalMilliseconds);
        }
        else
        {
            time = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// 使用前用 #if UNITY_EDITOR #endif 包裹
    /// </summary>
    private static bool isProgrammerDebug = true;

    private static bool isShowDebug = false;
    private static StringBuilder sb = new StringBuilder();

    /// <summary>
    /// 打印类里面的全部对象与值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="model"></param>
    public static string logToV<T>(T model)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        StringBuilder sbs = new StringBuilder();
        sbs.Remove(0, sbs.Length);
        Type t = model.GetType();
        var PropertyList = t.GetProperties();
        sbs.Append(model.ToString());

        if (PropertyList.Length > 0)
        {
            sbs.Append('[');
        }
        foreach (var item in PropertyList)
        {
            string name = item.Name;
            sbs.Append(name);
            sbs.Append(':');
            object value;
            try
            {
                value = item.GetValue(model, null);
            }
            catch (System.Exception ex)
            {
                value = null;
            }
            if (value is IList || value is IDictionary || value is Array)
            {
                sb.Append(vlistvdic(value));
            }
            else
            {
                sbs.Append(value);
            }
            sbs.Append(" ");
        }
        if (PropertyList.Length > 0)
        {
            sbs.Append(']');
        }
        string s = sbs.ToString();
        // log(s);
        return s;
#endif
        return "";
    }

    public static string vlistvdic(object obj)
    {
        StringBuilder sb = new StringBuilder();
        //log(obj.GetType().Name);
        if (obj is IList)
        {
            sb.Append("{ ");
            foreach (var item in (IList)obj)
            {
                if (item is string || item is int || item is float)
                {
                    sb.Append(item.ToString());
                }
                else if (item is IList || item is IDictionary || item is Array)
                {
                    sb.Append(vlistvdic(item));
                }
                else
                {
                    sb.Append(logToV(item));
                }
                sb.Append(" ");
            }
            sb.Append('}');
        }
        else if (obj is IDictionary)
        {
            sb.Append("{ ");
            foreach (var items in ((IDictionary)obj))
            {
                sb.Append("<");
                DictionaryEntry item = (DictionaryEntry)items;
                sb.Append(item.Key);
                sb.Append(' ');
                object vale = item.Value;
                if (vale is string || vale is int || vale is float)
                {
                    sb.Append(vale);
                }
                else if (vale is IList || vale is IDictionary || vale is Array)
                {
                    sb.Append(vlistvdic(item.Value));
                }
                else
                {
                    sb.Append(logToV(item.Value));
                }
                sb.Append(">");
            }
            sb.Append('}');
        }
        else if (obj is Array)
        {
            sb.Append("{ ");
            foreach (var item in (Array)obj)
            {
                if (item is string || item is int || item is float)
                {
                    sb.Append(item.ToString());
                }
                else if (item is IList || item is IDictionary || item is Array)
                {
                    sb.Append(vlistvdic(item));
                }
                else
                {
                    sb.Append((item));
                }
                sb.Append(" ");
            }
            sb.Append('}');
        }
        else
        {
            sb.Append(obj.ToString());
        }
        return sb.ToString().ToString();
    }

    /// <summary>
    /// debug obj对象,show 1表示显示迭代器类容,2表示显示迭代器类容并且显示类型
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static void log(object obj, byte show = 0)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (show == 0)
        {
            sb.Remove(0, sb.Length);
        }
        if (obj == null)
        {
            sb.Append("<null!!!>");
        }
        else if (obj is string || obj is int || obj is float)
        {
            sb.Append(obj.ToString());
        }
        else if (obj is Vector3 || obj is Vector2)
        {
            sb.Append(obj.ToString());
        }
        //else if (obj is HutongGames.PlayMaker.FsmStateAction)
        //{
        //    HutongGames.PlayMaker.FsmStateAction fsm = (HutongGames.PlayMaker.FsmStateAction)obj;
        //    string s = RootPath(fsm.Owner.transform) + "/" + fsm.Fsm.Name + "(fsm)." + fsm.Fsm.ActiveStateName + "(State) " + fsm.Name;
        //    sb.Append(s);
        //}
        else if (obj is GameObject || obj is Transform)
        {
            Transform v;
            if (obj is GameObject)
            {
                GameObject o = (GameObject)(obj);
                v = o.transform;
            }
            else
            {
                Transform o = (Transform)obj;
                v = o;
            }
            string name = v.name;
            string path = RootPath(v.transform);
            sb.Append(name);
            if (name != path)
            {
                sb.Append(" path: ");
                sb.Append(path);
            }
        }
        else if (obj is IList || obj is IDictionary || obj is Array)
        {
            sb.Append(vlistvdic(obj));
        }
        else
        {
            sb.Append(logToV(obj));
            if (show == 2)
            {
                sb.Append(' ');
                string ts = obj.GetType().ToString();
                sb.Append(ts);
            }
        }
        if (show == 0)
        {
            string s = sb.Replace("System.", "").Replace("Collections.", "").Replace("Generic.", "").Replace("Single", "f").Replace("Int32", "").ToString();

            switch (Showlevel)
            {
                case Level.normal_1:
                    UnityEngine.Debug.Log(s);
                    break;

                case Level.warning_2:
                    UnityEngine.Debug.LogWarning(s);
                    break;

                case Level.error_3:
                    lin(true);
                    UnityEngine.Debug.LogError(s);
                    lin(true);
                    break;
            }
        }
        return;
#endif
        return;
    }

    /// <summary>
    /// 带判断条件的输出,多个参数
    /// </summary>
    /// <param name="t"></param>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool log(bool t, params object[] obj)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (t)
        {
            log(obj);
        }
        return true;
#endif
        return false;
    }

    public static bool log(bool t, Level _Showlevel, params object[] obj)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (t)
        {
            log(_Showlevel, obj);
        }
        return true;
#endif
        return false;
    }

    public static bool log(Level _Showlevel, params object[] obj)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR

        Showlevel = _Showlevel;
        log(obj);
        Showlevel = Level.normal_1;

        return true;
#endif
        return false;
    }

    /// <summary>
    /// 输出多个参数
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool log(params object[] obj)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        sb.Remove(0, sb.Length);
        string str = "";
        string end = "";
        if (obj.Length > 1)
        {
            str = "<";
            end = ">,";
        }
        for (int i = 0; i < obj.Length; i++)
        {
            sb.Append(str);
            log(obj[i], 1);
            sb.Append(end);
        }
        string s = sb.Replace("System.", "").Replace("Collections.", "").Replace("Generic.", "").Replace("Single", "f").Replace("Int32", "").ToString();
        switch (Showlevel)
        {
            case Level.normal_1:
                UnityEngine.Debug.Log(s);
                break;

            case Level.warning_2:
                UnityEngine.Debug.LogWarning(s);
                break;

            case Level.error_3:
                //lin(true);
                UnityEngine.Debug.LogError(s);
                //lin(true);
                break;
        }
        return true;
#endif
        return false;
    }

    public static bool lin(bool isshow = true)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isshow)
        {
            UnityEngine.Debug.Log("----------------------------" + i++ + "--------------------------------");
        }
        return true;
#endif
        return false;
    }

    public static bool lin(string com, bool isshow = true)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isshow)
        {
            string s = string.Format("----------------------------{0}:{1}--------------------------------", com, i++);
            UnityEngine.Debug.Log(s);
        }
        return true;
#endif
        return false;
    }

    /// <summary>
    /// 测试代码是否报错
    /// </summary>
    /// <param name="LogicalSegment"></param>
    /// <returns></returns>
    public static bool tryCatch(Action LogicalSegment)
    {
        try
        {
            if (LogicalSegment != null)
            {
                LogicalSegment.Invoke();
            }
        }
        catch (System.Exception ex)
        {
            log("逻辑出错!!!!!!");
            log(ex.ToString());
            stop();
        }
        finally
        {
            lin(com: "完成");
        }
        return true;
    }

    public static bool logs(bool isok, Action LogicalSegment)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isok)
        {
            logs(LogicalSegment);
        }
        return true;
#endif
        return false;
    }

    public static bool logs(Action LogicalSegment)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        try
        {
            if (LogicalSegment != null)
            {
                LogicalSegment.Invoke();
            }
        }
        catch (System.Exception ex)
        {
            log("逻辑出错!!!!!!");
            log(ex.ToString());
            stop();
        }
        return true;
#endif
        return false;
    }

    public static bool logs<T>(bool isok, T obj, Action<T> LogicalSegment)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isok)
        {
            logs(obj, LogicalSegment);
        }
        return true;
#endif
        return false;
    }

    public static bool logs<T>(T obj, Action<T> LogicalSegment)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        try
        {
            LogicalSegment.Invoke(obj);
        }
        catch (System.Exception ex)
        {
            log("逻辑出错!!!!!!");
            log(ex.ToString());
            stop();
        }
        return true;
#endif
        return false;
    }

    public static bool tryCatch(Action<object> LogicalSegment, object obj)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isProgrammerDebug)
        {
            try
            {
                if (isShowDebug)
                {
                    lin(com: "测试逻辑开始");
                }

                if (LogicalSegment != null)
                {
                    LogicalSegment.Invoke(obj);
                }
                if (isShowDebug)
                {
                    lin(com: "测试逻辑成功");
                }
            }
            catch (System.Exception ex)
            {
                log("测试逻辑出错!!!!!!");
                log(ex.ToString());
                stop();
            }
            finally
            {
                if (isShowDebug)
                {
                    lin(com: "测试逻辑结束");
                }
            }
            return true;
        }
        else
        {
            return false;
        }
#endif
        return false;
    }

    private static Stopwatch sw = new Stopwatch();

    /// <summary>
    /// 测试代码运行时间
    /// </summary>
    /// <param name="LogicalSegment"></param>
    /// <returns></returns>
    public static bool TestRunTime(Action LogicalSegment)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        if (isProgrammerDebug)
        {
            try
            {
                if (LogicalSegment != null)
                {
                    sw.Reset();
                    sw.Start();
                    LogicalSegment.Invoke();
                    sw.Stop();
                    log("运行时间:" + sw.ElapsedMilliseconds.ToString() + "毫秒");
                }
            }
            catch (System.Exception ex)
            {
                log("测试逻辑出错!!!!!!");
                log(ex.ToString());
                stop();
            }
            finally
            {
                if (isShowDebug)
                {
                    log("测试逻辑结束");
                }
            }
            return true;
        }
        else
        {
            return false;
        }
#endif
        return false;
    }

    //清除控制台
    public static void ClearConsole()
    {
#if UNITY_EDITOR
        // This simply does "LogEntries.Clear()" the long way:
        var logEntries = System.Type.GetType("UnityEditorInternal.LogEntries,UnityEditor.dll");
        var clearMethod = logEntries.GetMethod("Clear", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
        clearMethod.Invoke(null, null);
#endif
    }

    /// <summary>
    /// 获取对象路径
    /// </summary>
    /// <param name="_node"></param>
    /// <param name="_root"></param>
    /// <returns></returns>
    public static string RootPath(Transform _node, Transform _root = null)
    {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
        string path = "";
        Transform m_curTransform = null;
        string RootName;
        if (_root == null)
        {
            _root = _node.root;
        }
        RootName = _root.name;
        if (RootName != _node.name)
        {
            m_curTransform = _node;
            path = m_curTransform.name;
            m_curTransform = m_curTransform.parent;

            while (!RootName.Equals(m_curTransform.name.ToString()))
            {
                path = path.Insert(0, m_curTransform.name.ToString() + "/");
                m_curTransform = m_curTransform.parent;
            }
        }
        else
        {
            path = _node.name;
        }
        return path;
#endif
        return "";
    }

    //暂停
    public static void stop()
    {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPaused = true;
#endif
    }

#if UNITY_EDITOR

    #region 定位到输出位置

    private static string fnName = "debug:log";
    private static string className = "debug.cs";

    //双击代码到打印debug的位置
    [UnityEditor.Callbacks.OnOpenAssetAttribute(0)]
    private static bool OnOpenAsset(int instanceID, int line)
    {
        string stackTrace = GetStackTrace();
        if (!string.IsNullOrEmpty(stackTrace) && stackTrace.Contains(fnName))
        {
            System.Text.RegularExpressions.Match matches = System.Text.RegularExpressions.Regex.Match(stackTrace, @"\(at (.+)\)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            string pathLine = "";
            while (matches.Success)
            {
                pathLine = matches.Groups[1].Value;

                if (!pathLine.Contains(className))
                {
                    int splitIndex = pathLine.LastIndexOf(":");
                    string path = pathLine.Substring(0, splitIndex);
                    line = System.Convert.ToInt32(pathLine.Substring(splitIndex + 1));
                    string fullPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets"));
                    fullPath = fullPath + path;
                    UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line);
                    break;
                }
                matches = matches.NextMatch();
            }
            return true;
        }
        return false;
    }

    private static string GetStackTrace()
    {
        var ConsoleWindowType = typeof(UnityEditor.EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow");
        var fieldInfo = ConsoleWindowType.GetField("ms_ConsoleWindow", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        var consoleInstance = fieldInfo.GetValue(null);
        if (consoleInstance != null)
        {
            if ((object)UnityEditor.EditorWindow.focusedWindow == consoleInstance)
            {
                var ListViewStateType = typeof(UnityEditor.EditorWindow).Assembly.GetType("UnityEditor.ListViewState");
                fieldInfo = ConsoleWindowType.GetField("m_ListView", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                var listView = fieldInfo.GetValue(consoleInstance);
                fieldInfo = ListViewStateType.GetField("row", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
                int row = (int)fieldInfo.GetValue(listView);
                fieldInfo = ConsoleWindowType.GetField("m_ActiveText", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                string activeText = fieldInfo.GetValue(consoleInstance).ToString();
                return activeText;
            }
        }
        return null;
    }

    #endregion 定位到输出位置

#endif
}